using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

namespace SteeringBehaviors
{
    public partial class TaskForce
    {
        #region HELPER METHODS

        /// <summary>
        /// Either set the focus forward vector and point to that of the 
        /// first ship (leader) or calculate the average forward vector 
        /// and average position to serve as the focus forward vector and 
        /// point respectively.
        /// </summary>
        private void CalculateFocus()
        {
            if (StickToLeader)
            {
                // TODO: focus to leader
				focusPoint = ships[0].Position;
				focusForward = ships[0].GetForward();
            }
            else
            {
                // TODO: focus to task force averages
				Vector3 avgPosition = new Vector3();
				Vector3 avgForward = new Vector3();
				for (int i = 0; i < ships.Count; i++)
				{
					avgPosition += ships[i].Position;
					avgForward += ships[i].GetForward();
				}
				avgPosition.X = avgPosition.X / ships.Count;
				avgPosition.Y = avgPosition.Y / ships.Count;
				avgPosition.Z = avgPosition.Z / ships.Count;
				avgForward.Normalize();
				focusPoint = avgPosition;
				focusForward = avgForward;
            }
        }

        /// <summary>
        /// Determines the acceleration vector to apply to a ship based
        /// on the alignment algorithm
        /// </summary>
        /// <returns>the acceleration vector to apply</returns>
        private Vector3 GetAlignmentAcceleration()
        {
            Vector3 acceleration = new Vector3();
            if (AlignmentStrength != 0)
            {
                // TODO: Compute acceleration vector based on alignment algorithm.
                // Scale this vector by the AlignmentStrength property.
				//CalculateFocus();
				acceleration = focusForward;
				acceleration.Scale(alignmentStrength);
            }
            return acceleration;
        }

        /// <summary>
        /// Determines the acceleration vector to apply to the provided 
        /// ship based on the cohesion algorithm
        /// </summary>
        /// <param name="ship">the provided ship</param>
        /// <returns>the acceleration vector to apply</returns>
        private Vector3 GetCohesionAcceleration(Ship ship)
        {
            Vector3 acceleration = new Vector3();
            if (CohesionStrength != 0)
            {
                // TODO: Compute acceleration vector based on cohesion algorithm.
                // Set the length of this vector to the CohesionStrength property.
				//CalculateFocus();
				acceleration = focusPoint - ship.Position;
				acceleration.Normalize();
				acceleration.Scale(cohesionStrength);
            }
            return acceleration;
        }

        /// <summary>
        /// Determines the acceleration vector to apply to the provided 
        /// ship based on the separation algorithm
        /// </summary>
        /// <param name="ship">the provided ship</param>
        /// <returns>the acceleration vector to apply</returns>
        private Vector3 GetSeparationAcceleration(Ship ship)
        {
            Vector3 acceleration = new Vector3();
            if (SeparationStrength != 0)
            {
                int otherShipIndex = 0;
                if (PredictCollision(ship, out otherShipIndex))
                {
                    // TODO: Compute acceleration vector based on separation algorithm.
                    // Set the length of this vector to the SeparationStrength property.
					Ship nearestShip = ships[otherShipIndex];
					Vector3 differenceVector = new Vector3();
					acceleration = ship.Position - nearestShip.Position;
					acceleration.Normalize();
					acceleration.Scale(SeparationStrength);
                }
            }
            return acceleration;
        }

        #endregion

        #region INTERFACE METHODS

        /// <summary>
        /// Updates all ships currently assigned to this task force
        /// </summary>
        /// <param name="delta">seconds since last update</param>
        public virtual void Update(float delta)
        {
            if (ships.Count > 0)
            {
                // TODO: Calculate the flock focus.
				CalculateFocus();
                for (int i = 0; i < ships.Count; ++i)
                {
                    if (!(i == 0 && StickToLeader) && ships[i].Idle)
                    {
                        Vector3 accumulator = new Vector3();

                        // TODO: Use acculmulator to calculate the sum of each
                        // steering behavior acceleration vector.  Scale this
                        // sum by the product of the ship's task force speed 
                        // and time. Then add this accumulator to the ship's 
                        // velocity vector.
						accumulator = GetAlignmentAcceleration() + GetCohesionAcceleration(ships[i]) + GetSeparationAcceleration(ships[i]);
						accumulator *= ships[i].TaskForceSpeed * delta;
						ships[i].Velocity += accumulator;
                    }
                    ships[i].Update(delta);
                }
            }
        }

        #endregion
    }
}